package com.sinping.qh.service.app.MessageInfo.impl;

import com.google.common.collect.Lists;
import com.mongodb.AggregationOutput;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.sinping.qh.api.support.*;
import com.sinping.qh.domain.user.MessageInfoDomain;
import com.sinping.qh.domain.user.UserInfo;
import com.sinping.qh.dto.admin.user.MessageInfoDto;
import com.sinping.qh.dto.auth.UserSessionDTO;
import com.sinping.qh.query.message.MessageInfoQuery;
import com.sinping.qh.repository.mongo.MessageInfoRepository;
import com.sinping.qh.repository.mongo.user.UserInfoRepository;
import com.sinping.qh.service.MongoManager;
import com.sinping.qh.service.app.MessageInfo.IMessageInfoService;


import com.sinping.qh.service.app.auth.ISessionMongoService;
import com.sinping.qh.service.auth.ISessionService;
import com.sinping.qh.service.common.CommonDbConst;
import com.sinping.qh.service.redis.RedisService;
import com.sinping.qh.utils.mapper.BeanMapper;
import com.sinping.qh.utils.mapper.JsonMapper;
import com.sinping.qh.utils.misc.IdGenerator;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.*;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;


@Service
public class MessageInfoImpl implements IMessageInfoService {

    private final  static Logger logger = LoggerFactory.getLogger(MessageInfoImpl.class);
    @Autowired
    MessageInfoRepository messageInfoRepository;

    @Qualifier(value = "sessionServiceRedisImpl")
    @Autowired
    ISessionService iSessionService;

    @Autowired
    ISessionMongoService sessionMongoService;

    @Autowired
    MongoManager mongoManager;

    @Autowired
    private MongoTemplate template;

    @Autowired
    private UserInfoRepository userInfoRepository;

    @Value(value = "${qh.upload.urlPath}")
    private String urlPath;

    @Autowired
    RedisService redisService;

    @Override
    public ResDto addMessageInfo(HttpServletRequest httpServletRequest,MessageInfoDto messageInfoDto) {

        String token =httpServletRequest.getHeader(Const.TOKEN_NAME);
        UserSessionDTO userSessionDTO = iSessionService.getSessionByToken(token);
        if (userSessionDTO == null){
            return new ResDto(Const.PARAM_ERROR,"用户未登录");
        }

        if (StringUtils.isBlank(userSessionDTO.getId())){
            return new ResDto(Const.SERVER_ERROR,"获取用户信息错误");
        }

        String userId = userSessionDTO.getId();
        String username = userSessionDTO.getUsername();

        try{
            MessageInfoDomain messageInfoDomain = BeanMapper.map(messageInfoDto,MessageInfoDomain.class);

            messageInfoDomain.setId(IdGenerator.uuid2());
            messageInfoDomain.setPublishId(userId); //发布人id
            messageInfoDomain.setPublishName(username);//发布人姓名
            messageInfoDomain.setStatus("0");
            messageInfoDomain.setGmtCreated(new Date());//创建时间
            messageInfoDomain.setGmtModified(new Date());//更新时间

            if(messageInfoDomain.getType().equals("1")){ //把用户id都存进来
                ArrayList<String> ids = new ArrayList<>();
                List<UserInfo> list = userInfoRepository.findAll();
                for (UserInfo info:list) {
                    ids.add(info.getId());
                }
                messageInfoDomain.setNotReceiveIds(ids);
            }

            MessageInfoDomain save  = messageInfoRepository.save(messageInfoDomain);
            if (save == null){
                return new ResDto(Const.SERVER_ERROR,"通知消息保存失败");
            }
            return new ResDto(Const.SUCCESS,"保存成功",messageInfoDomain.getId());
        }
        catch (Exception e){
            logger.error("数据异常{}",e);
            return new ResDto(Const.SERVER_ERROR,"数据异常");
        }

    }

    @Override
    public ResDto updateMessageInfo(HttpServletRequest httpServletRequest, MessageInfoDto messageInfoDto) {
        String token =httpServletRequest.getHeader(Const.TOKEN_NAME);
        UserSessionDTO userSessionDTO = iSessionService.getSessionByToken(token);
        if (userSessionDTO == null){
            return new ResDto(Const.PARAM_ERROR,"用户未登录");
        }

        if (StringUtils.isBlank(userSessionDTO.getId())){
            return new ResDto(Const.SERVER_ERROR,"获取用户信息错误");
        }

        String userId = userSessionDTO.getId();
        String username = userSessionDTO.getUsername();

        try {

            if (StringUtils.isBlank(messageInfoDto.getId())){
                return new ResDto(Const.PARAM_ERROR,"没有传人通知消息id");
            }
            if (messageInfoDto.getReceiveIds() == null){
                return new ResDto(Const.PARAM_ERROR,"没有传人接收人id");
            }

            MessageInfoDomain messageInfoDomain = messageInfoRepository.findMessageInfoDomainByIdAndStatus(messageInfoDto.getId(),"0");
            if (messageInfoDomain == null){
                return new ResDto(Const.SERVER_ERROR,"没有此记录");
            }

            messageInfoDomain.getReceiveIds().addAll(messageInfoDto.getReceiveIds()); //新增的
            messageInfoDomain.getNotReceiveIds().removeAll(messageInfoDto.getReceiveIds()); //移除

            messageInfoDomain.setReceiveIds(messageInfoDomain.getReceiveIds());  //更新ReceiveIds
            messageInfoDomain.setNotReceiveIds(messageInfoDomain.getNotReceiveIds());  //更新ReceiveIds

            messageInfoDomain.setGmtModified(new Date()); //更新修改日期
            messageInfoDomain.setPublishId(userId);  //更新发布人
            messageInfoDomain.setPublishName(username);
            MessageInfoDomain save  = messageInfoRepository.save(messageInfoDomain);
            if (save == null){
                return new ResDto(Const.SERVER_ERROR,"通知消息更新失败");
            }
            return new ResDto(Const.SUCCESS,"更新成功");
        }
        catch (Exception e){
            logger.error("数据异常{}",e);
            return new ResDto(Const.SERVER_ERROR,"数据异常");
        }

    }

    @Override
    public ResDto getMessageInfoById(String id) {
        try{
            ResDto resDto = new ResDto();
            MessageInfoDomain messageInfoDomain = messageInfoRepository.findOne(id);
            if (messageInfoDomain == null){
                resDto.setStatus(Const.DATA_ERROR);
                resDto.setMsg("没有该记录");
                return resDto;
            }
            MessageInfoDto messageInfoDto = BeanMapper.map(messageInfoDomain,MessageInfoDto.class);

            if (messageInfoDto.getType().equals("1")){
                if (StringUtils.isNotBlank(messageInfoDto.getLinkUrl())){
                    messageInfoDto.setLinkUrl(urlPath+messageInfoDto.getLinkUrl());
                }
            }


            String json = JsonMapper.defaultMapper().toJson(messageInfoDto);
            resDto.setDatas(json);
            resDto.setMsg("成功");
            resDto.setStatus(Const.SUCCESS);
            return resDto;
        }
        catch (Exception e){
            logger.error("数据异常{}",e);
            return new ResDto(Const.SERVER_ERROR,"数据异常");
        }
    }

    @Override
    public ResDto getMessageInfoFrontPage(String userId,FrontPage frontPage) {


        MessageInfoQuery query;
        Map<String,String> conditionMap = frontPage.getCondition();
        if (conditionMap == null || conditionMap.isEmpty()){
            query = new MessageInfoQuery();
        }
        else {
             String conditonStr = JsonMapper.defaultMapper().toJson(conditionMap);
             MessageInfoDto messageInfoDto = JsonMapper.defaultMapper().fromJson(conditonStr,MessageInfoDto.class);
            query = new MessageInfoQuery();
            query.setTitle(messageInfoDto.getTitle());
            query.setStartGmtCreated(frontPage.getStartDate());
            query.setEndGmtCreated(frontPage.getEndDate());
            query.setType(messageInfoDto.getType());
            if (messageInfoDto.getType().equals("1")){  //如果是消息
                List<String> list = new ArrayList<>();
                list.add(userId);
                query.setReceiveIds(list);
            }
        }

        query.setStatus("0");

        try {

            Pageable pageable = new PageRequest(frontPage.getPage() - 1, frontPage.getSize(), new Sort(Sort.Direction.DESC, "gmt_created"));
            Page<MessageInfoDomain> messageInfoDomainPage = mongoManager.findPage(query, pageable, MessageInfoDomain.class);
            List<MessageInfoDomain> list = messageInfoDomainPage.getContent();
            for (MessageInfoDomain model:list) {
                if (model.getType().equals("1")){
                    if (StringUtils.isNotBlank(model.getLinkUrl())){
                        model.setLinkUrl(urlPath+model.getLinkUrl());
                    }
                }

            }


            ResDto resDto = new ResDto(ConstEum.SUCCESS);
            resDto.setMsg("成功");
            ResDtoUtil.defaultUtil().pageDomainDtoToFrontDto(resDto, messageInfoDomainPage, MessageInfoDto.class, frontPage);
            return resDto;
        } catch (Exception e) {
            e.printStackTrace();
            return new ResDto(Const.SERVER_ERROR,"数据异常");
        }
    }

    @Override
    public ResDto deleteMessageInfoById(String id) {
        try {
            MessageInfoDomain messageInfoDomain = messageInfoRepository.findOne(id);
            if (messageInfoDomain == null){
                return new ResDto(Const.SERVER_ERROR,"没有该记录");
            }
            messageInfoDomain.setStatus(CommonDbConst.DB_DELETE_LOGICAL);
            MessageInfoDomain messageInfoDomain1 = messageInfoRepository.save(messageInfoDomain);
            if (messageInfoDomain1 == null){
                return new ResDto(Const.SERVER_ERROR,"删除失败");
            }
            return new ResDto(Const.SUCCESS,"删除成功");
        }
        catch (Exception e){
            logger.error("数据异常{}",e);
            return new ResDto(Const.SERVER_ERROR,"删除失败，数据异常");
        }
    }

    @Override
    public ResDto deleteMessageInfoByDocId(String docId) {
        try {
            MessageInfoDomain messageInfoDomain = messageInfoRepository.findMessageInfoDomainByDocId(docId);
            if (messageInfoDomain == null){
                return new ResDto(Const.SERVER_ERROR,"没有该记录");
            }
            messageInfoDomain.setStatus(CommonDbConst.DB_DELETE_LOGICAL);
            MessageInfoDomain messageInfoDomain1 = messageInfoRepository.save(messageInfoDomain);
            if (messageInfoDomain1 == null){
                return new ResDto(Const.SERVER_ERROR,"删除失败");
            }
            return new ResDto(Const.SUCCESS,"删除成功");
        }
        catch (Exception e){
            logger.error("数据异常{}",e);
            return new ResDto(Const.SERVER_ERROR,"删除失败，数据异常");
        }
    }

    @Override
    public ResDto getMessageInfoByMsg(String msg) {
        try {
            Map<String,Object> map = JsonMapper.defaultMapper().fromJson(msg,Map.class);
            if (map == null){
                return null;
            }
            int pageno = Integer.parseInt(map.get("page_current").toString());
            int pagesize = Integer.parseInt(map.get("page_size").toString());
            PageRequest page = new PageRequest(pageno-1,pagesize,null);

            ArrayList resultsByPage= getMessage(map,true);

            ArrayList resultsByNoPage= getMessage(map,false);

            Page<MessageInfoDomain> CheckRecords=new PageImpl<>(resultsByPage, page, resultsByNoPage.size());

            FrontPage frontPage =new FrontPage();

            frontPage.setTotal((int)CheckRecords.getTotalElements());

            frontPage.setPage(pageno);

            frontPage.setPages(CheckRecords.getTotalPages());
            frontPage.setRecords(CheckRecords.getContent());

            if (resultsByPage.size() >0){
                return new ResDto(Const.SUCCESS,"成功", JsonMapper.defaultMapper().toJson(frontPage));
            }
            else {
                return new ResDto(Const.SUCCESS,"成功", "{}");
            }
        }
        catch (Exception e){
            return null;
        }
    }

    private ArrayList getMessage(Map<String,Object> map,boolean isPage)
    {
        List<DBObject> list = new ArrayList<>();
            /*按检查项查询*/
        Map<String,Object> match1Map = new HashMap<>();
        if (StringUtils.isNotBlank(map.get("id").toString()) ){
            String id = map.get("id").toString();
            match1Map.put("doc_id",id);
        }
        DBObject match1 = new BasicDBObject("$match",match1Map);


        String sendType = map.get("send_type").toString();

            /* 创建Lab的lookup操作 */
        Map<String,String> userMap = new HashMap<>();
        userMap.put("from","tb_user_info");
        userMap.put("foreignField","_id");
        if (sendType.equals("1")){  //已发送
            userMap.put("localField","receive_ids");
            userMap.put("as","userinfo");
        }
        else if (sendType.equals("2")){  //未发送
            userMap.put("localField","not_receive_ids");
            userMap.put("as","userinfo");
        }
        else {
            return null;
        }
        DBObject lookUp = new BasicDBObject("$lookup",userMap);


            /* 创建unwind操作 */
        DBObject unwind = new BasicDBObject("$unwind","$userinfo");

            /*按选择条件查询*/
        Map<String,Object> match2Map = new HashMap<>();
        if (StringUtils.isNotBlank(map.get("full_name").toString()) ){
            String name = map.get("full_name").toString();

            Map<String,Object> nameMap = new HashMap<>();
            nameMap.put("$regex",name);
            match2Map.put("userinfo.full_name",nameMap);
        }
        if (StringUtils.isNotBlank(map.get("role_id").toString()) ){
            String role_id = map.get("role_id").toString();
            match2Map.put("userinfo.role_id",role_id);
        }
        if (StringUtils.isNotBlank(map.get("unit_id").toString()) ){
            String unit_id = map.get("unit_id").toString();
            match2Map.put("userinfo.unit_id",unit_id);
        }
        DBObject match2 = new BasicDBObject("$match",match2Map);

            /* 创建project1操作 */
        Map<String,Integer> projectMap = new HashMap<>();
        projectMap.put("userinfo._id",1);
        projectMap.put("userinfo.full_name",1);
        projectMap.put("userinfo.unit_name",1);
        projectMap.put("userinfo.role_name",1);
        DBObject project = new BasicDBObject("$project",projectMap);



        DBCollection dbCollection = template.getCollection("tb_message_info");
        list.add(match1);
        list.add(lookUp);
        list.add(unwind);
        list.add(match2);
        list.add(project);
        if(isPage) {
            //创建分页
            int pageno = Integer.parseInt(map.get("page_current").toString());
            int pagesize = Integer.parseInt(map.get("page_size").toString());
            DBObject skip = new BasicDBObject("$skip", (pageno - 1) * pagesize);
            DBObject limit = new BasicDBObject("$limit", pagesize);
            list.add(skip);
            list.add(limit);
        }

        AggregationOutput aggregate = dbCollection.aggregate(list);
        ArrayList results = (ArrayList)aggregate.results();
        return results;
    }

    @Override
    public  ResDto getLatestMessageInfo(HttpServletRequest httpServletRequest) {

        /*
        * db.getCollection('tb_message_info').find({$or:[{'receive_ids':18},{'receive_ids':{$exists:false}}]}).sort({gmt_created:-1}).limit(1);
        */
        try{
            String token =httpServletRequest.getHeader(Const.TOKEN_NAME);
            String session =redisService.hgetByUserinfo(token);
            com.sinping.qh.dto.mongo.auth.UserSessionDTO sessionByToken =
                    JsonMapper.defaultMapper().fromJson(session,com.sinping.qh.dto.mongo.auth.UserSessionDTO.class);

            UserInfo userInfo = sessionByToken.getUserInfo();
            List<AggregationOperation> operations = Lists.newArrayList();
            Criteria criteria = new Criteria();
            Criteria criteria1  = Criteria.where("receive_ids").in(userInfo.getId());
            Criteria criteria2  = Criteria.where("receive_ids").exists(false);
            Criteria criteria3  = Criteria.where("status").is("0");
            criteria.orOperator(criteria1,criteria2).andOperator(criteria3);


            operations.add(Aggregation.match(criteria));
            operations.add(Aggregation.sort(new Sort(Sort.Direction.DESC,"gmt_created")));
            operations.add(Aggregation.limit(1));

            Aggregation aggregation = Aggregation.newAggregation(operations);
            String table = template.getCollectionName(MessageInfoDomain.class);
            AggregationResults<MessageInfoDomain> results = template.aggregate(aggregation, table, MessageInfoDomain.class);


            MessageInfoDomain messageInfoDomain = results.getUniqueMappedResult();


            if (messageInfoDomain == null){
                return new ResDto(Const.SERVER_ERROR,"没有通知记录");
            }

            MessageInfoDto messageInfoDto = BeanMapper.map(messageInfoDomain,MessageInfoDto.class);

            if (messageInfoDto.getType().equals("1")){
                if (StringUtils.isNotBlank(messageInfoDto.getLinkUrl())){
                    messageInfoDto.setLinkUrl(urlPath + messageInfoDto.getLinkUrl());
                }
            }

            String json = JsonMapper.defaultMapper().toJson(messageInfoDto);

            ResDto resDto = new ResDto();
            resDto.setMsg("成功");
            resDto.setStatus(Const.SUCCESS);
            resDto.setDatas(json);
            return resDto;
        }
        catch (Exception e){
            logger.error("数据异常{}",e);
            return new ResDto(Const.SERVER_ERROR,"获取失败，数据异常");
        }
    }
}
